#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

template<class T>
class SmartPtr
{
public:
	//把资源交给对象来管理，在对象的生命周期内，资源有效，对象生命周期到了，资源释放
	//像指针一样使用
	SmartPtr(T* ptr)
		:_ptr(ptr)
	{
		cout << "SmartPtr(T* ptr)" << endl;
	}

	~SmartPtr()
	{
		cout << "~SmartPtr()" << endl;
		delete _ptr;
	}

	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
private:
	T* _ptr;
};

int func(int x,int y)
{
	if (y == 0)
	{
		throw "除0异常";
	}

	return x / y;

}

void test1(int x, int y)
{
	SmartPtr<pair<int, int>> ptr1 (new pair<int, int>(1, 1));
	SmartPtr<pair<int, int>> ptr2 (new pair<int, int>(2, 2));
	SmartPtr<pair<int, int>> ptr3 (new pair<int, int>(2, 2));
	cout << ptr1->first << endl;
	cout << ptr2->first << endl;
	cout << ptr3->first << endl;


	SmartPtr<pair<string, string>> ptr4 = (new pair<string, string>("xxxx", "yyyyy"));
	SmartPtr<int> ptr5 = (new int(2));
	cout << ptr4->first << " " << ptr4->second << endl;
	cout << *ptr5 << endl;



	func(x, y);
}
#include"SmartPtr.h"

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a = 0)" << endl;
	}
	~A()
	{
		cout << _a << " -> ~A()" << endl;

		_a = 0;
	}
	int _a;

};

//C++98  auto_ptr
void test2()
{
	//转移资源的管理权：被拷贝对象的资源管理权转移给拷贝对象-->会导致被拷贝对象悬空
	auto_ptr<A> ptr7(new A(1));
	auto_ptr<A> ptr8(new A(2));
	
	//cyq::auto_ptr<pair<int, int>> ptr1(new pair<int, int>(1, 1));
	//cyq::auto_ptr<pair<int, int>> ptr2(new pair<int, int>(2, 2));
	//cyq::auto_ptr<pair<int, int>> ptr3 = ptr1;

	auto_ptr<pair<int, int>> ptr1(new pair<int, int>(1, 1));
	auto_ptr<pair<int, int>> ptr2(new pair<int, int>(2, 2));
	auto_ptr<pair<int, int>> ptr3 = ptr1;

	//不能访问
	//cout << ptr1->first << endl;
	cout << ptr2->first << endl;
	cout << ptr3->first << endl;

}

//c++11 unique_ptr
void test3()
{
	unique_ptr<A> ptr1(new A(1));
	unique_ptr<A> ptr2(new A(2));

	//直接禁止拷贝和赋值
	//unique_ptr<A> ptr3(ptr1);
	//ptr2 = ptr1;

	cyq::unique_ptr<A> ptr3(new A(1));
	cyq::unique_ptr<A> ptr4(new A(2));
	cout << (*ptr3)._a << endl;
	cout << ptr4->_a << endl;
	//cyq::unique_ptr<A> ptr5(ptr3);
	//ptr4 = ptr3;

}

//shared_ptr
void test4()
{
	//允许拷贝
	shared_ptr<A> ptr1(new A(1));
	shared_ptr<A> ptr2(new A(2));
	shared_ptr<A> ptr3(ptr1);
	ptr2 = ptr1;
	ptr1->_a++;
	ptr2->_a++;
	ptr3->_a++;
	cout << ptr1->_a << endl;

	cyq::shared_ptr<A> ptr4(new A(1));
	cyq::shared_ptr<A> ptr5(new A(2));
	cyq::shared_ptr<A> ptr6(ptr4);
	cyq::shared_ptr<A> ptr7(ptr4);
	cyq::shared_ptr<A> ptr8(new A(3));
	cyq::shared_ptr<A> ptr9(new A(4));

	ptr8 = ptr6;
	ptr9 = ptr6;

	//自己给自己赋值
	cyq::shared_ptr<A> ptr10(new A(5));
	ptr10 = ptr10;
	ptr8 = ptr9;

}

struct Node
{
	A _val;
	//cyq::shared_ptr<Node> _next;
	//cyq::shared_ptr<Node> _prev;

	cyq::weak_ptr<Node> _next;
	cyq::weak_ptr<Node> _prev;
};

void test5()
{
	cyq::shared_ptr<Node> ptr1(new Node);
	cyq::shared_ptr<Node> ptr2(new Node);

	//weak_ptr的原理--不增加引用计数，也不参与资源的释放，可以访问资源
	cout << ptr1.use_count() << endl;
	cout << ptr2.use_count() << endl;

	//导致循环引用的问题-->导致内存泄露-->改成weak_ptr-->不具备RAII，专门用来解决shared_ptr引起的循环引用问题
	//不支持原生指针初始化，可以用weak_ptr去拷贝和赋值，用shared_ptr去赋值
	ptr1->_next = ptr2;
	ptr2->_prev = ptr1;

	cout << ptr1.use_count() << endl;
	cout << ptr2.use_count() << endl;

	//访问
	cout << (ptr2->_prev)->_val._a++ << endl;


}

template<class T>
class DeleteArray
{
public:
	void operator()(T* ptr)
	{
		delete[] ptr;
	}
};

//定制删除器
void test6()
{
	cyq::shared_ptr<A> ptr1(new A[10], DeleteArray<A>());
	cyq::shared_ptr<A> ptr2(new A[10], [](A* ptr) {delete[] ptr; });
	cyq::shared_ptr<FILE> ptr3(fopen("test.text", "w"), [](FILE* ptr) {
		cout << "fclose:" << ptr << endl;
		fclose(ptr); });

	cyq::shared_ptr<A> ptr4(new A(1));

	/*shared_ptr<A> ptr1(new A[10], DeleteArray<A>());
	shared_ptr<A> ptr2(new A[10], [](A* ptr) {delete[] ptr; });
	shared_ptr<FILE> ptr3(fopen("test.text", "w"), [](FILE* ptr) {
		cout << "fclose:" << ptr << endl;
		fclose(ptr); });*/


}
int main()
{
	/*int a, b;
	cin >> a >> b;
	try
	{
		test1(a, b);
	}
	catch (const char* e)
	{
		cout << e << endl;
	}*/

	test2();
	cout << "--------------------------------------" << endl;

	test3();
	cout << "--------------------------------------" << endl;

	test4();
	cout << "--------------------------------------" << endl;

	test5();
	cout << "--------------------------------------" << endl;

	test6();
	cout << "--------------------------------------" << endl;

	return 0;
}